#pragma once

#include "Singleton.h"
#include "QuestLog.h"

class LocatableObject;

class QuestMgr : public Singleton<QuestMgr>
{
public:
	QuestMgr();
	virtual ~QuestMgr();

	bool LoadQuests();

	GErrorCode HandleAcceptQuest(Player* pPlayer, LocatableObject* pLObj, const QuestPrototype* pQuestProto, QuestLog** pQuestLogPtr = NULL);
	GErrorCode HandleCancelQuest(Player* pPlayer, LocatableObject* pLObj, uint32 questUniqueKey);
	GErrorCode HandleSubmitQuest(Player* pPlayer, LocatableObject* pLObj, uint32 questUniqueKey);

	GErrorCode HandleEnterQuestGuide(Player* pPlayer, LocatableObject* pLObj, uint32 questTypeID, uint32 questUniqueKey = 0);

	void InitAllQuestWatchStatus(Player* pPlayer);
	void RefreshQuestWatchStatus(Player* pPlayer, uint32 questTypeID);
	void RefreshQuestWatchStatus4LevelDirty(Player* pPlayer);
	void RefreshQuestWatchStatus4QuestStatusDirty(Player* pPlayer, uint32 questTypeID);
	void RefreshQuestWatchStatus4ChequeValueDirty(Player* pPlayer, ChequeType chequeType);
	void RefreshQuestWatchStatus4ItemCountDirty(Player* pPlayer, uint32 itemTypeID);

	void SendObjCareNoWatchStatusQuests(Player* pPlayer, LocatableObject* pLObj);

	void OnQuestAccept(Player* pPlayer, QuestLog* pQuestLog);
	void OnQuestFinish(Player* pPlayer, QuestLog* pQuestLog);
	void OnQuestFailed(Player* pPlayer, QuestLog* pQuestLog);
	void OnQuestCancel(Player* pPlayer, QuestLog* pQuestLog);
	void OnQuestSubmit(Player* pPlayer, QuestLog* pQuestLog);

private:
	void CostQuestReqCheques(Player* pPlayer, const QuestPrototype* pQuestProto, CHEQUE_FLOW_TYPE flowType);
	void DestroyQuestReqItems(Player* pPlayer, const QuestPrototype* pQuestProto, ITEM_FLOW_TYPE flowType);
	void RefundQuestReqCheques(Player* pPlayer, const QuestPrototype* pQuestProto, CHEQUE_FLOW_TYPE flowType);
	void RefundQuestReqItems(Player* pPlayer, const QuestPrototype* pQuestProto, ITEM_FLOW_TYPE flowType);
	void ReceiveQuestInitCheques(Player* pPlayer, const QuestPrototype* pQuestProto, CHEQUE_FLOW_TYPE flowType);
	void ReceiveQuestInitItems(Player* pPlayer, const QuestPrototype* pQuestProto, ITEM_FLOW_TYPE flowType);
	void RetrieveQuestInitCheques(Player* pPlayer, const QuestPrototype* pQuestProto, CHEQUE_FLOW_TYPE flowType);
	void RetrieveQuestInitItems(Player* pPlayer, const QuestPrototype* pQuestProto, ITEM_FLOW_TYPE flowType);
	void ReceiveQuestRewardCheques(Player* pPlayer, const QuestPrototype* pQuestProto, CHEQUE_FLOW_TYPE flowType);
	void ReceiveQuestRewardItems(Player* pPlayer, const QuestPrototype* pQuestProto, ITEM_FLOW_TYPE flowType);

	QUEST_STATUS CalcQuestStatus(Player* pPlayer, const QuestPrototype* pQuestProto);

	QUEST_STATUS CalcQuestStatus4Script(Player* pPlayer, const QuestPrototype* pQuestProto);
	void AcceptQuest4Script(Player* pPlayer, const QuestPrototype* pQuestProto);

	void RunQuestScript4Event(Player* pPlayer, QuestLog* pQuestLog, QuestWhenType type);

	GErrorCode IsQuestObjInstMatchable(Player* pPlayer, LocatableObject* pLObj, const QuestObjInst& questObjInst);

	std::vector<const QuestPrototype*> m_allWatchStatusQuests;
	std::vector<const QuestPrototype*> m_allWatchStatusQuests4LvReq;
	std::unordered_map<uint32, std::vector<const QuestPrototype*>> m_allWatchStatusQuests4QuestReq;
	std::unordered_map<ChequeType, std::vector<const QuestPrototype*>> m_allWatchStatusQuests4ChequeReq;
	std::unordered_map<uint32, std::vector<const QuestPrototype*>> m_allWatchStatusQuests4ItemReq;

	std::unordered_map<uint32, std::vector<const QuestPrototype*>> m_allObjCareNoWatchStatusQuests[(int)QuestObjType::Count];
};

#define sQuestMgr (*QuestMgr::instance())
